package com.zm.demo.core.concurrent;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static java.lang.System.out;

/**
 * @author zoum
 * @create 2019/6/18 17:29
 */
public class ConditionDemo<T> {

    Lock lock = new ReentrantLock();
    Condition full = lock.newCondition();
    Condition empty = lock.newCondition();
    List<T> list = new ArrayList<>(3);


    public void put(T t){
            if (lock.tryLock()) {
                try {
                    if (list.size() >= 3) {
                        try {
                            out.println(Thread.currentThread().getName() + "-full await" + t);
                            full.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    out.println(Thread.currentThread().getName() + "-put " + t);
                    list.add(t);
                    empty.signalAll();
                    return;
                }finally {
                    lock.unlock();
                }

            }else {
                try {
                    Thread.sleep(500L);
                    out.println("put lock fail");
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
    }

    public T get(){
            if (lock.tryLock()){
                try {
                    if (list.size() == 0){
                        try {
                            out.println(Thread.currentThread().getName() + "-empty await");
                            empty.await();
                        } catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                    T t = list.remove(0);
                    out.println(Thread.currentThread().getName() + "-get " + t);
                    full.signalAll();
                    return t;
                }finally {
                    lock.unlock();
                }

            }else {
                try {
                    Thread.sleep(500L);
                    out.println("get lock fail");
                }catch (Exception e){
                    e.printStackTrace();
                }
                return null;
            }
    }


    public static void main(String[] args){
        ConditionDemo<Integer> conditionDemo = new ConditionDemo<>();
        ExecutorService pool = Executors.newCachedThreadPool();

        for (int i = 0; i < 30; i++) {
            pool.submit(() -> conditionDemo.get());
        }

        for (int i = 0; i < 30; i++) {
            final int j=i;
            pool.submit(() -> conditionDemo.put(j));
        }
        pool.shutdown();
    }

}
